"""
角色API模块

提供角色管理相关的所有API接口，包括：
- 角色的增删改查
- 角色权限管理
- 用户角色关联
- 权限验证
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
from datetime import datetime, timezone
from typing import Optional, List
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from db.models import Role, Permission, RolePermission, User, UserRole
from db.session import get_db
from apis.user_api import get_current_user
from services.permission import require_permission, PermissionCodes

router = APIRouter(prefix="/roles", tags=["角色管理"])

security = HTTPBearer()

class RoleCreate(BaseModel):
    """角色创建请求模型"""
    name: str
    code: str
    description: Optional[str] = None
    is_active: bool = True

class RoleUpdate(BaseModel):
    """角色更新请求模型"""
    name: Optional[str] = None
    code: Optional[str] = None
    description: Optional[str] = None
    is_active: Optional[bool] = None

class RoleResponse(BaseModel):
    """角色响应模型"""
    id: int
    name: str
    code: str
    description: Optional[str]
    is_active: bool
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True

class RoleListResponse(BaseModel):
    roles: List[RoleResponse]
    total: int
    page: int
    pageSize: int

class RolePermissionRequest(BaseModel):
    permission_ids: List[int]

@router.post("/", response_model=RoleResponse, summary="创建角色")
@require_permission(PermissionCodes.ROLE_CREATE)
async def create_role(
    role: RoleCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    创建新角色
    
    Args:
        role: 角色创建数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        RoleResponse: 创建的角色信息
        
    Raises:
        HTTPException: 角色代码已存在或权限不足时抛出异常
    """
    # 检查角色代码是否已存在
    result = await db.execute(select(Role).where(Role.code == role.code))
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="角色代码已存在"
        )
    
    # 创建角色
    db_role = Role(
        name=role.name,
        code=role.code,
        description=role.description,
        is_active=role.is_active
    )
    
    db.add(db_role)
    await db.commit()
    await db.refresh(db_role)
    
    return db_role

@router.get("/", response_model=RoleListResponse, summary="获取角色列表")
@require_permission(PermissionCodes.ROLE_READ)
async def get_all_roles(
    page: int = 1,
    pageSize: int = 10,
    search: str = "",
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取角色列表（分页）
    
    Args:
        page: 页码
        pageSize: 每页数量
        search: 搜索关键词
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        RoleListResponse: 角色列表和分页信息
        
    Raises:
        HTTPException: 权限不足时抛出异常
    """
    # 构建查询
    query = select(Role)
    
    # 添加搜索条件
    if search:
        query = query.where(Role.name.contains(search) | Role.code.contains(search))
    
    # 获取总数
    count_query = select(func.count(Role.id))
    if search:
        count_query = count_query.where(Role.name.contains(search) | Role.code.contains(search))
    
    total_result = await db.execute(count_query)
    total = total_result.scalar() or 0
    
    # 添加分页
    query = query.offset((page - 1) * pageSize).limit(pageSize)
    
    # 执行查询
    result = await db.execute(query)
    roles = result.scalars().all()
    
    return RoleListResponse(
        roles=[RoleResponse(
            id=role.id,
            name=role.name,
            code=role.code,
            description=role.description,
            is_active=role.is_active,
            created_at=role.create_time,
            updated_at=role.update_time
        ) for role in roles],
        total=total,
        page=page,
        pageSize=pageSize
    )

@router.get("/{role_id}", response_model=RoleResponse, summary="获取角色详情")
@require_permission(PermissionCodes.ROLE_READ)
async def get_role(
    role_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取角色详情
    
    Args:
        role_id: 角色ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        RoleResponse: 角色详细信息
        
    Raises:
        HTTPException: 角色不存在或权限不足时抛出异常
    """
    result = await db.execute(select(Role).where(Role.id == role_id))
    role = result.scalar_one_or_none()
    
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在"
        )
    
    return role

@router.put("/{role_id}", response_model=RoleResponse, summary="更新角色")
@require_permission(PermissionCodes.ROLE_UPDATE)
async def update_role(
    role_id: int,
    role_update: RoleUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    更新角色信息
    
    Args:
        role_id: 角色ID
        role_update: 角色更新数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        RoleResponse: 更新后的角色信息
        
    Raises:
        HTTPException: 角色不存在或权限不足时抛出异常
    """
    # 查找角色
    result = await db.execute(select(Role).where(Role.id == role_id))
    role = result.scalar_one_or_none()
    
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在"
        )
    
    # 更新角色信息
    if role_update.name is not None:
        role.name = role_update.name
    
    if role_update.code is not None:
        # 检查角色代码是否已被使用
        existing_role = await db.execute(select(Role).where(
            Role.code == role_update.code,
            Role.id != role_id
        ))
        if existing_role.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="角色代码已存在"
            )
        role.code = role_update.code
    
    if role_update.description is not None:
        role.description = role_update.description
    
    if role_update.is_active is not None:
        role.is_active = role_update.is_active
    
    # 更新时间
    role.update_time = datetime.now(timezone.utc)
    
    await db.commit()
    await db.refresh(role)
    
    return role

@router.delete("/{role_id}", summary="删除角色")
@require_permission(PermissionCodes.ROLE_DELETE)
async def delete_role(
    role_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    删除角色
    
    Args:
        role_id: 角色ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        dict: 删除结果
        
    Raises:
        HTTPException: 角色不存在、有用户使用或权限不足时抛出异常
    """
    # 查找角色
    result = await db.execute(select(Role).where(Role.id == role_id))
    role = result.scalar_one_or_none()
    
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在"
        )
    
    # 检查是否有用户使用此角色
    user_role_result = await db.execute(select(UserRole).where(UserRole.role_id == role_id))
    if user_role_result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="该角色下有用户，无法删除"
        )
    
    # 删除角色权限关联
    await db.execute(select(RolePermission).where(RolePermission.role_id == role_id))
    await db.delete(role)
    await db.commit()
    
    return {"message": "角色删除成功"}

@router.get("/{role_id}/permissions", summary="获取角色权限")
@require_permission(PermissionCodes.ROLE_READ)
async def get_role_permissions(
    role_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取角色的权限列表
    
    Args:
        role_id: 角色ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        dict: 权限列表
        
    Raises:
        HTTPException: 角色不存在或权限不足时抛出异常
    """
    # 查找角色
    result = await db.execute(select(Role).where(Role.id == role_id))
    role = result.scalar_one_or_none()
    
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在"
        )
    
    # 获取角色权限
    query = select(Permission).join(RolePermission).where(RolePermission.role_id == role_id)
    result = await db.execute(query)
    permissions = result.scalars().all()
    
    return {"permissions": permissions}

@router.post("/{role_id}/permissions")
@require_permission(PermissionCodes.ROLE_UPDATE)
async def assign_role_permissions(
    role_id: int,
    request: RolePermissionRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    # 查找角色
    result = await db.execute(select(Role).where(Role.id == role_id))
    role = result.scalar_one_or_none()
    
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在"
        )
    
    # 验证权限是否存在
    for permission_id in request.permission_ids:
        permission_result = await db.execute(select(Permission).where(Permission.id == permission_id))
        if not permission_result.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"权限ID {permission_id} 不存在"
            )
    
    # 删除现有权限关联
    await db.execute(select(RolePermission).where(RolePermission.role_id == role_id))
    
    # 添加新的权限关联
    for permission_id in request.permission_ids:
        role_permission = RolePermission(role_id=role_id, permission_id=permission_id)
        db.add(role_permission)
    
    await db.commit()
    
    return {"message": "权限分配成功"}

@router.get("/{role_id}/users")
@require_permission(PermissionCodes.ROLE_READ)
async def get_role_users(
    role_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    # 查找角色
    result = await db.execute(select(Role).where(Role.id == role_id))
    role = result.scalar_one_or_none()
    
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在"
        )
    
    # 获取角色用户
    query = select(User).join(UserRole).where(UserRole.role_id == role_id)
    result = await db.execute(query)
    users = result.scalars().all()
    
    return {"users": users}
